package com.kylin.weixin.common.xml.bean;


import com.google.gson.GsonBuilder;

import com.kylin.qq.weixin.mp.aes.AesException;
import com.kylin.qq.weixin.mp.aes.WXBizMsgCrypt;
import com.kylin.weixin.common.xml.utils.XStreamCDataConverter;
import com.kylin.weixin.common.xml.utils.XStreamTransformer;
import com.kylin.weixin.common.xml.utils.XmlUtils;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamConverter;
import lombok.*;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.NodeList;

import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

/**
 * Program Name: dajia-wxapplet
 * <p>
 * Description: 微信推送的xml格式消息
 * <p>
 * Created by tongzhq on 2019/12/9 0009 20:04
 *
 * @author tongzhq
 * @version 1.0
 */
@Data
@XStreamAlias("xml")
public class WeChatXmlMessage implements Serializable {

    private static final Logger LOGGER = LoggerFactory.getLogger(WeChatXmlMessage.class);
    private static final long serialVersionUID = -1726905188405398687L;

    private String appID;

    /**
     * 使用dom4j解析的存放所有xml属性和值的map.
     */
    private Map<String, Object> allFieldsMap;

    ///////////////////////
    // 以下都是微信推送过来的消息的xml的element所对应的属性
    ///////////////////////

    /**
     * 第三方平台授权推送特有 第三方appId
     */
    @XStreamAlias("AppId")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String wx3rdAppId;

    /**
     * 授权凭据
     */
    @XStreamAlias("ComponentVerifyTicket")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String componentVerifyTicket;

    @XStreamAlias("InfoType")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String infoType;

    @XStreamAlias("AuthorizerAppid")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String appId;
//   * 第三方平台授权推送特有


    @XStreamAlias("ToUserName")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String toUser;

    @XStreamAlias("FromUserName")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String fromUser;

    @XStreamAlias("CreateTime")
    private Long createTime;

    @XStreamAlias("MsgType")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String msgType;

    @XStreamAlias("Content")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String content;

    @XStreamAlias("MenuId")
    private Long menuId;

    @XStreamAlias("MsgId")
    private Long msgId;

    @XStreamAlias("PicUrl")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String picUrl;

    @XStreamAlias("MediaId")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String mediaId;

    @XStreamAlias("Format")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String format;

    @XStreamAlias("ThumbMediaId")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String thumbMediaId;

    @XStreamAlias("Location_X")
    private Double locationX;

    @XStreamAlias("Location_Y")
    private Double locationY;

    @XStreamAlias("Scale")
    private Double scale;

    @XStreamAlias("Label")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String label;

    @XStreamAlias("Title")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String title;

    @XStreamAlias("Description")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String description;

    @XStreamAlias("Url")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String url;

    @XStreamAlias("Event")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String event;

    @XStreamAlias("EventKey")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String eventKey;

    @XStreamAlias("Ticket")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String ticket;

    @XStreamAlias("Latitude")
    private Double latitude;

    @XStreamAlias("Longitude")
    private Double longitude;

    @XStreamAlias("Precision")
    private Double precision;

    @XStreamAlias("Recognition")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String recognition;

    @XStreamAlias("UnionId")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String unionId;

    private String shareCardID;

    /***********************企业微信特有****************************/
    private String corpID;

    @XStreamAlias("AgentID")
    private String agentID;

    @XStreamAlias("ChangeType")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String changeType;

    @XStreamAlias("TagId")
    private int tagId;

    @XStreamAlias("UserID")
    private String userID;

    @XStreamAlias("ExternalUserID")
    private String externalUserID;

    @XStreamAlias("State")
    private String state;

    @XStreamAlias("WelcomeCode")
    private String welcomeCode;

    @XStreamAlias("AddUserItems")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String addUserItems;

    @XStreamAlias("DelUserItems")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private String delUserItems;

    @XStreamAlias("AddPartyItems")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private List<Integer> addPartyItems;

    @XStreamAlias("DelPartyItems")
    @XStreamConverter(value = XStreamCDataConverter.class)
    private List<Integer> delPartyItems;

    private String companyID;



    public static WeChatXmlMessage fromXml(String xml) {
        final WeChatXmlMessage xmlMessage = XStreamTransformer.fromXml(WeChatXmlMessage.class, xml);
        xmlMessage.setAllFieldsMap(XmlUtils.xml2Map(xml));
        return xmlMessage;
    }

    public static WeChatXmlMessage fromXml(InputStream is) {
        String xml;
        try {
            xml = IOUtils.toString(is, StandardCharsets.UTF_8);
            LOGGER.info("明文xml={}", xml);
            return fromXml(xml);
        } catch (IOException e) {
            LOGGER.info("【IO to String error】：{}", e);
        }
        return null;
    }

    /**
     * 从加密字符串转换.
     *
     * @param encryptedXml      密文
     * @param token             公众平台上，开发者设置的token
     * @param encodingAesKey    公众平台上，开发者设置的EncodingAESKey
     * @param appId             公众平台appid
     * @param timestamp         时间戳
     * @param nonce             随机串
     * @param msgSignature      签名串
     */
    public static WeChatXmlMessage fromEncryptedXml(String encryptedXml, String token, String encodingAesKey, String appId,
                                                  String timestamp, String nonce, String msgSignature) {
        try {
            LOGGER.info("解密前的原始xml消息内容：{}", encryptedXml);
            WXBizMsgCrypt wxBizMsgCrypt = new WXBizMsgCrypt(token, encodingAesKey, appId);
            String plainText = wxBizMsgCrypt.decryptMsg(msgSignature, timestamp, nonce, encryptedXml);
            LOGGER.info("解密后的原始xml消息内容：{}", plainText);
            return fromXml(plainText);
        } catch (AesException e) {
            LOGGER.info("解密XML消息异常：{}", e);
        }
        return null;
    }

    public static WeChatXmlMessage fromEncryptedXml(InputStream is, String token, String encodingAesKey, String appId, String timestamp,
                                                  String nonce, String msgSignature) {
        try {
            return fromEncryptedXml(IOUtils.toString(is, StandardCharsets.UTF_8), token, encodingAesKey, appId, timestamp, nonce, msgSignature);
        } catch (IOException e) {
            LOGGER.info("【IO to String error】：{}", e);
        }
        return null;
    }


}